package Simulator;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class Field {
	private static final Random rand = new Random();

	// The depth and width of the field.
	private int depth, width;
	// Storage for the actors.
	private ActorInterface[][] field;

	public Field(int depth, int width) {
		this.depth = depth;
		this.width = width;
		field = new ActorInterface[depth][width];
	}

	public void clear() {
		for (int row = 0; row < depth; row++) {
			for (int col = 0; col < width; col++) {
				field[row][col] = null;
			}
		}
	}

	public void place(ActorInterface actorNew) {
		Location location = actorNew.getLocation();
		ActorInterface actor = getActorAt(location);
		if (!(actor instanceof ActorInterface)) {
			field[location.getRow()][location.getCol()] = actorNew;
		}
	}

	public ActorInterface getActorAt(Location location) {
		return getActorAt(location.getRow(), location.getCol());
	}

	public ActorInterface getActorAt(int row, int col) {
		return field[row][col];
	}

	public Location randomAdjacentLocation(Location location) {
		int row = location.getRow();
		int col = location.getCol();
		// Generate an offset of -1, 0, or +1 for both the current row and col.
		int nextRow = row + rand.nextInt(3) - 1;
		int nextCol = col + rand.nextInt(3) - 1;
		// Check in case the new location is outside the bounds.
		if (nextRow < 0 || nextRow >= depth || nextCol < 0 || nextCol >= width) {
			return location;
		} else if (nextRow != row || nextCol != col) {
			return new Location(nextRow, nextCol);
		} else {
			return location;
		}
	}

	public Location freeAdjacentLocation(Location location) {
		Iterator<Location> adjacent = adjacentLocations(location);
		while (adjacent.hasNext()) {
			Location next = adjacent.next();
			if (field[next.getRow()][next.getCol()] == null) {
				return next;
			}
		}
		// check whether current location is free
		if (field[location.getRow()][location.getCol()] == null) {
			return location;
		} else {
			return null;
		}
	}

	public Iterator<Location> adjacentLocations(Location location) {
		int row = location.getRow();
		int col = location.getCol();
		List<Location> locations = new LinkedList<Location>();
		for (int roffset = -1; roffset <= 1; roffset++) {
			int nextRow = row + roffset;
			if (nextRow >= 0 && nextRow < depth) {
				for (int coffset = -1; coffset <= 1; coffset++) {
					int nextCol = col + coffset;
					// Exclude invalid locations and the original location.
					if (nextCol >= 0 && nextCol < width
							&& (roffset != 0 || coffset != 0)) {
						locations.add(new Location(nextRow, nextCol));
					}
				}
			}
		}
		Collections.shuffle(locations, rand);
		return locations.iterator();
	}

	public int getDepth() {
		return depth;
	}

	public int getWidth() {
		return width;
	}
}
